package com.meadhall.sync2cloud.ui;

import java.awt.CardLayout;
import java.io.File;
import java.util.List;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;

import com.meadhall.sync2cloud.L2RSync;
import com.meadhall.sync2cloud.R2LSync;
import com.rackspacecloud.client.cloudfiles.FilesClient;
import com.rackspacecloud.client.cloudfiles.FilesContainer;

/**
 * Main UI class for CloudSync. Presents interface and allows user to control the application. Does not perform any actual synchronization itself.
 * 
 * @author Marshall Levin
 */
public class Sync2Cloud extends javax.swing.JFrame {

	private static final long serialVersionUID = -2380406227716145441L;

	private FilesClient client;
	private String containerName;
	private File localRoot;
	private SwingWorker<Void, String> l2r;
	private SwingWorker<Void, String> r2l;

	public Sync2Cloud() {
		initComponents();
	}

	// GEN-BEGIN:initComponents
	// <editor-fold defaultstate="collapsed" desc="Generated Code">
	private void initComponents() {

		directionGroup = new javax.swing.ButtonGroup();
		cardPanel = new javax.swing.JPanel();
		loginPanel = new javax.swing.JPanel();
		loginTitle = new javax.swing.JLabel();
		instructions = new javax.swing.JLabel();
		username = new javax.swing.JTextField();
		usernameLabel = new javax.swing.JLabel();
		passwordLabel = new javax.swing.JLabel();
		password = new javax.swing.JTextField();
		loginButton = new javax.swing.JButton();
		loginStatusLabel = new javax.swing.JLabel();
		mainPanel = new javax.swing.JPanel();
		mainTitle = new javax.swing.JLabel();
		containerLabel = new javax.swing.JLabel();
		containerList = new javax.swing.JComboBox();
		localDirectory = new javax.swing.JTextField();
		localDirectoryButton = new javax.swing.JButton();
		directionL2R = new javax.swing.JRadioButton();
		directionR2L = new javax.swing.JRadioButton();
		directionLabel = new javax.swing.JLabel();
		startButton = new javax.swing.JButton();
		mainStatusLabel = new javax.swing.JLabel();
		stopButton = new javax.swing.JButton();
		menuBar = new javax.swing.JMenuBar();
		fileMenu = new javax.swing.JMenu();
		exitMenuItem = new javax.swing.JMenuItem();

		setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

		cardPanel.setLayout(new java.awt.CardLayout());

		loginTitle.setFont(new java.awt.Font("Arial", 1, 18));
		loginTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
		loginTitle.setText("CloudSync");
		loginTitle.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);

		instructions.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
		instructions.setText("Please enter your Rackspace CloudFiles credentials");

		username.setFont(new java.awt.Font("Tahoma", 0, 10));
		username.setMinimumSize(new java.awt.Dimension(168, 19));

		usernameLabel.setLabelFor(username);
		usernameLabel.setText("Username");

		passwordLabel.setLabelFor(password);
		passwordLabel.setText("API Key");

		password.setFont(new java.awt.Font("Tahoma", 0, 10));
		password.setMinimumSize(new java.awt.Dimension(168, 19));

		loginButton.setText("Login");
		loginButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				loginButtonActionPerformed(evt);
			}
		});

		loginStatusLabel.setFont(new java.awt.Font("Tahoma", 0, 10));
		loginStatusLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
		loginStatusLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
		loginStatusLabel.setBorder(javax.swing.BorderFactory.createTitledBorder("Status"));

		javax.swing.GroupLayout loginPanelLayout = new javax.swing.GroupLayout(loginPanel);
		loginPanel.setLayout(loginPanelLayout);
		loginPanelLayout.setHorizontalGroup(loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
				loginPanelLayout.createSequentialGroup().addContainerGap().addGroup(
						loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
								loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
										loginPanelLayout.createSequentialGroup().addGroup(
												loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(instructions, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 380,
														Short.MAX_VALUE).addComponent(loginTitle, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)).addContainerGap()).addGroup(
										javax.swing.GroupLayout.Alignment.TRAILING,
										loginPanelLayout.createSequentialGroup().addGroup(
												loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING).addComponent(loginStatusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 267, javax.swing.GroupLayout.PREFERRED_SIZE).addGroup(
														loginPanelLayout.createSequentialGroup().addGroup(loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING).addComponent(passwordLabel).addComponent(usernameLabel)).addGap(18,
																18, 18).addGroup(
																loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false).addComponent(username, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
																		Short.MAX_VALUE).addComponent(password, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))).addGap(68, 68, 68))).addGroup(
								javax.swing.GroupLayout.Alignment.TRAILING, loginPanelLayout.createSequentialGroup().addComponent(loginButton).addGap(162, 162, 162)))));
		loginPanelLayout.setVerticalGroup(loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
				loginPanelLayout.createSequentialGroup().addContainerGap().addComponent(loginTitle).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addComponent(instructions).addPreferredGap(
						javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addGroup(
						loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(username, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
								.addComponent(usernameLabel)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addGroup(
						loginPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(password, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
								.addComponent(passwordLabel)).addGap(25, 25, 25).addComponent(loginButton).addGap(18, 18, 18).addComponent(loginStatusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE).addGap(63,
						63, 63)));

		cardPanel.add(loginPanel, "loginCard");

		mainTitle.setFont(new java.awt.Font("Arial", 1, 18));
		mainTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
		mainTitle.setText("CloudSync");
		mainTitle.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);

		containerLabel.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
		containerLabel.setText("Please choose a CloudFiles container");

		containerList.setFont(new java.awt.Font("Tahoma", 0, 10));
		containerList.setModel(new DefaultComboBoxModel());
		containerList.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				containerListActionPerformed(evt);
			}
		});

		localDirectory.setEditable(false);
		localDirectory.setFont(new java.awt.Font("Tahoma", 0, 10));
		localDirectory.setHorizontalAlignment(javax.swing.JTextField.CENTER);
		localDirectory.setText(new File(".").getAbsolutePath());

		localDirectoryButton.setText("Please choose a local directory");
		localDirectoryButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				localDirectoryButtonActionPerformed(evt);
			}
		});

		directionGroup.add(directionL2R);
		directionL2R.setSelected(true);
		directionL2R.setText("Local to Server");
		directionL2R.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
		directionL2R.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);

		directionGroup.add(directionR2L);
		directionR2L.setText("Server to Local");

		directionLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
		directionLabel.setText("Please select a synchronization direction");

		startButton.setText("Start");
		startButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				startButtonActionPerformed(evt);
			}
		});

		mainStatusLabel.setFont(new java.awt.Font("Tahoma", 0, 10));
		mainStatusLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
		mainStatusLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP);
		mainStatusLabel.setBorder(javax.swing.BorderFactory.createTitledBorder("Status"));

		stopButton.setText("Stop");
		stopButton.setEnabled(false);
		stopButton.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				stopButtonActionPerformed(evt);
			}
		});

		javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
		mainPanel.setLayout(mainPanelLayout);
		mainPanelLayout.setHorizontalGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
				mainPanelLayout.createSequentialGroup().addGroup(
						mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(mainPanelLayout.createSequentialGroup().addContainerGap().addComponent(mainTitle, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE))
								.addGroup(
										mainPanelLayout.createSequentialGroup().addGap(14, 14, 14).addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING).addComponent(containerLabel).addComponent(localDirectoryButton))
												.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addGroup(
														mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false).addComponent(localDirectory, javax.swing.GroupLayout.Alignment.LEADING).addComponent(containerList,
																javax.swing.GroupLayout.Alignment.LEADING, 0, 177, Short.MAX_VALUE))).addGroup(mainPanelLayout.createSequentialGroup().addGap(103, 103, 103).addComponent(directionLabel)).addGroup(
										mainPanelLayout.createSequentialGroup().addGap(92, 92, 92).addGroup(
												mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING).addComponent(startButton).addComponent(directionL2R, javax.swing.GroupLayout.PREFERRED_SIZE, 111,
														javax.swing.GroupLayout.PREFERRED_SIZE)).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addGroup(
												mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(directionR2L).addComponent(stopButton))).addGroup(
										mainPanelLayout.createSequentialGroup().addContainerGap().addComponent(mainStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE))).addContainerGap()));
		mainPanelLayout.setVerticalGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
				mainPanelLayout.createSequentialGroup().addContainerGap().addComponent(mainTitle).addGap(18, 18, 18).addGroup(
						mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(containerList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
								.addComponent(containerLabel)).addGap(18, 18, 18).addGroup(
						mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(localDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
								.addComponent(localDirectoryButton)).addGap(18, 18, 18).addComponent(directionLabel).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addGroup(
						mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
								mainPanelLayout.createSequentialGroup().addComponent(directionR2L).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(stopButton)).addGroup(
								mainPanelLayout.createSequentialGroup().addComponent(directionL2R).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(startButton))).addPreferredGap(
						javax.swing.LayoutStyle.ComponentPlacement.RELATED, 31, Short.MAX_VALUE).addComponent(mainStatusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE).addContainerGap()));

		cardPanel.add(mainPanel, "mainCard");

		fileMenu.setText("File");

		exitMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q, java.awt.event.InputEvent.CTRL_MASK));
		exitMenuItem.setText("Exit");
		exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				exitMenuItemActionPerformed(evt);
			}
		});
		fileMenu.add(exitMenuItem);

		menuBar.add(fileMenu);

		setJMenuBar(menuBar);

		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
		getContentPane().setLayout(layout);
		layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(cardPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE));
		layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(cardPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE));

		pack();
	}// </editor-fold>

	// GEN-END:initComponents

	/**
	 * Stops any background synchronizing that may be happening. Updates UI to disable "Stop" button and enable "Start" button.
	 */
	private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {
		if (l2r != null) {
			l2r.cancel(true);
		}
		if (r2l != null) {
			r2l.cancel(true);
		}
		startButton.setEnabled(true);
		stopButton.setEnabled(false);
	}

	/**
	 * Starts background synchronizing based on the type selected. Uses SwingWorker to perform tasks without tying up main UI thread. Updates UI to disable "Start" button and enable "Stop" button.
	 */
	private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {
		try {
			startButton.setEnabled(false);
			stopButton.setEnabled(true);
			if (directionL2R.isSelected()) {
				// sync L2R
				l2r = new L2RSync(localRoot, containerName, client, mainStatusLabel);
				l2r.execute();
			} else {
				// sync R2L
				r2l = new R2LSync(localRoot, containerName, client, mainStatusLabel);
				r2l.execute();
			}
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, "Error: " + e.getLocalizedMessage());
		}
	}

	/**
	 * Updates container based on user selection.
	 */
	private void containerListActionPerformed(java.awt.event.ActionEvent evt) {
		containerName = containerList.getSelectedItem().toString();
	}

	/**
	 * Updates local directory based on user selection.
	 */
	private void localDirectoryButtonActionPerformed(java.awt.event.ActionEvent evt) {
		final JFileChooser fileChooser = new JFileChooser();
		File startDir = localRoot;
		if (localRoot == null) {
			startDir = new File(".");
		}
		fileChooser.setCurrentDirectory(startDir);
		fileChooser.setFileSelectionMode(javax.swing.JFileChooser.DIRECTORIES_ONLY);
		int returnVal = fileChooser.showOpenDialog(this);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			File fileChosen = fileChooser.getSelectedFile();
			localDirectory.setText(fileChosen.getAbsolutePath());
			localRoot = fileChosen;
		}
	}

	/**
	 * Attempts to authenticate against the CloudFiles service based on the username and API key provided by the user.
	 */
	private void loginButtonActionPerformed(java.awt.event.ActionEvent evt) {

		// Log in
		client = new FilesClient(username.getText(), password.getText());
		try {
			boolean loginSuccess = client.login();
			if (!loginSuccess) {
				loginStatusLabel.setText("Incorrect username or password.");
			} else {
				((CardLayout) cardPanel.getLayout()).show(cardPanel, "mainCard");
				ComboBoxModel model = getContainers();
				containerList.setModel(model);
				containerName = model.getSelectedItem().toString();
			}
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, "Error: " + e.getLocalizedMessage());
		}

	}

	/**
	 * Fetches the list of containers owned by the user.
	 * 
	 * @return a ComboBoxModel containing the names of the containers
	 */
	private ComboBoxModel getContainers() {
		DefaultComboBoxModel model = new DefaultComboBoxModel();
		try {
			List<FilesContainer> containers = client.listContainers();
			for (FilesContainer container : containers) {
				model.addElement(container.getName());
			}
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, "Error: " + e.getLocalizedMessage());
		}
		return model;
	}

	private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_exitMenuItemActionPerformed
		System.exit(0);
	}// GEN-LAST:event_exitMenuItemActionPerformed

	public static void main(String args[]) {
		java.awt.EventQueue.invokeLater(new Runnable() {
			public void run() {
				new Sync2Cloud().setVisible(true);
			}
		});
	}

	// GEN-BEGIN:variables
	// Variables declaration - do not modify
	private javax.swing.JPanel cardPanel;
	private javax.swing.JLabel containerLabel;
	private javax.swing.JComboBox containerList;
	private javax.swing.ButtonGroup directionGroup;
	private javax.swing.JRadioButton directionL2R;
	private javax.swing.JLabel directionLabel;
	private javax.swing.JRadioButton directionR2L;
	private javax.swing.JMenuItem exitMenuItem;
	private javax.swing.JMenu fileMenu;
	private javax.swing.JLabel instructions;
	private javax.swing.JTextField localDirectory;
	private javax.swing.JButton localDirectoryButton;
	private javax.swing.JButton loginButton;
	private javax.swing.JPanel loginPanel;
	private javax.swing.JLabel loginStatusLabel;
	private javax.swing.JLabel loginTitle;
	private javax.swing.JPanel mainPanel;
	private javax.swing.JLabel mainStatusLabel;
	private javax.swing.JLabel mainTitle;
	private javax.swing.JMenuBar menuBar;
	private javax.swing.JTextField password;
	private javax.swing.JLabel passwordLabel;
	private javax.swing.JButton startButton;
	private javax.swing.JButton stopButton;
	private javax.swing.JTextField username;
	private javax.swing.JLabel usernameLabel;
	// End of variables declaration//GEN-END:variables

}